package jd.monitor.attach;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.commons.lang.StringUtils;

import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;

import jd.monitor.attach.config.BeanConfig;
import jd.monitor.attach.config.BeanContext;
import jd.monitor.attach.config.BeanRoot;
import jd.monitor.attach.util.PathUtil;
import jd.monitor.attach.util.XmlSerializableUtil;

/**
 * 
 * @author wangyankai
 *
 */
public class AgentInitialization {
	
//	private final static Logger logger = LoggerFactory.getLogger(AgentInitialization.class);
	
	private String xmlConfig = BeanContext.AGENTCONFIGNAME;
	private String agentJar = BeanContext.AGENTJARNAME;
	private Timer timer = new Timer(); 
	private AttachTask attachTask = new AttachTask();
	private ReplaceTask replaceTask = new ReplaceTask();
	
	public AgentInitialization(){
		try {
			init();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public AgentInitialization(String xmlConfig, String agentJar) {
		this.xmlConfig = xmlConfig;
		this.agentJar = agentJar;
		try {
//			init();
			monitorChange();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}


	/**
	 * 初始化配置文件、attach
	 * @throws AttachNotSupportedException
	 * @throws IOException
	 * @throws AgentLoadException
	 * @throws AgentInitializationException
	 */
	protected void init() throws Exception {
		// 读取BeanRoot
		System.out.println("filePath = "+xmlConfig);
		String xmlStr = XmlSerializableUtil.getXmlConfig(xmlConfig) ;
		if(xmlStr != null){
			BeanContext.getContext().put(BeanContext.AGENTCONFIG, xmlStr) ;
			try {
				initAttach();
			} catch (Exception e) {
				e.printStackTrace();;
			} 
		}
		
	}

	/*
	 * 加载attach
	 */
	private void initAttach() throws Exception {
			String name = ManagementFactory.getRuntimeMXBean().getName();
			String pid = name.split("@")[0];
//			String path = PathUtil.revisionFilePath(agentJar) ;
			String pathJar = agentJar ;
			if (agentJar.indexOf(File.separator) < 0){
				pathJar = PathUtil.getPathForJar();
				pathJar = pathJar.substring(0, pathJar.lastIndexOf("/")+1)+agentJar;
			}
			System.out.println("ppid = "+pid  +"  path="+pathJar);
			URLClassLoader classloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
//			URL[] urls = classloader.getURLs();
//			for (URL url : urls) {
//				System.out.println(url);
//			}
			Method add = URLClassLoader.class.getDeclaredMethod("addURL", new Class[] { URL.class });
			add.setAccessible(true);
			String jhome = System.getProperty("java.home");
			String toolsJar = jhome.substring(0, jhome.length() - 4) +"/lib/tools.jar" ;
			System.out.println("  toolsJar"+toolsJar);
			add.invoke(classloader, new Object[]{ new File(toolsJar).toURI().toURL() });
//			urls = classloader.getURLs();
//			System.out.println(" -============ ");
//			for (URL url : urls) {
//				System.out.println(url);
//			}

			
			VirtualMachine vm = VirtualMachine.attach(pid);
			vm.loadAgent(pathJar,PathUtil.revisionFilePath(xmlConfig));
			vm.detach();
	}
	
	/**
	 * 监测配置文件是否改变
	 */
	private void monitorChange(){
		System.out.println(" monitorXmlChange start");
		String xmlC = XmlSerializableUtil.getXmlConfig(xmlConfig);
		System.out.println("xmlC = "+ xmlC.length());
		BeanRoot beanRoot = XmlSerializableUtil.deSerializeXML(BeanRoot.class, xmlC, true);
		System.out.println(" beanConfig start");
		BeanConfig beanConfig = beanRoot.getBeanList().get(0);
		
		if(StringUtils.isNotEmpty(beanConfig.getTimerAttach())){
			System.out.println(" attachTask start");
			Long timerAttach = Long.valueOf(beanConfig.getTimerAttach());
			timer.schedule(attachTask, timerAttach, timerAttach);
			
		}else{
			System.out.println(" monitorXmlChange start");
			timer.schedule(replaceTask, 5000L, 5000L);
		}
	}
	
	class AttachTask extends TimerTask{

		@Override
		public void run() {
			try {
				init();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}
	
	class ReplaceTask extends TimerTask{

		@Override
		public void run() {
			try {
				String xmlStr = XmlSerializableUtil.getXmlConfig(xmlConfig);
				if (StringUtils.isNotBlank(xmlStr)
						&& !xmlStr.equals(BeanContext.getContext().get(BeanContext.AGENTCONFIG))) {
					System.out.println(" reload xml ");
					init();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
	}

	
}

